package frog;

import egg.Egg;
import env.Application;
import env.Env;
import env.Zone;
import frog.brain.Cell;
import frog.brain.CellGroup;
import frog.brain.Input;
import frog.brain.Output;

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Frog {
    //forg的生命状态
    public boolean alive=true;
    public int moveCount = 0; // how many times moved

    //编译控制开关
    private boolean allowVariation = false;


    //脑细胞
    public float brainRadius;

    List<Cell> cells=new ArrayList<Cell>();

    /** 运动细胞的输入区在脑中的坐标，先随便取就可以了，以后再考虑放到蛋里去进化 */
    public static Zone moveUp = new Zone(500, 50, 10);
    public static Zone moveDown = new Zone(500, 100, 10);
    public static Zone moveLeft = new Zone(500, 150, 10);
    public static Zone moveRight = new Zone(500, 200, 10);
    public static Zone moveRandom = new Zone(500, 300, 10);

    int x;
    int y;

    public long energy=10000;
    public Egg egg;

    static final Random r = new Random();



    static Image frogImg;
    static {
        try {
            frogImg = ImageIO.read(new FileInputStream(Application.CLASSPATH + "\\frog.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public Frog(int x, int y, Egg egg){
        this.x=x;
        this.y=y;
        //保留egg信息
        this.egg=egg;
        //首先判断egg的重要属性cellgroups是否为空
        if(egg.cellgroups==null)
            throw new IllegalArgumentException("Illega egg cellgroups arguments"+egg.cellgroups);
        //Frog遗传egg的brainraduis
        this.brainRadius=egg.brainRadius;
        //开始根据egg的遗传信息创建frog的cell,通过遍历每个cellgroups的成员来复制cell
        for(int k=0;k<egg.cellgroups.length;k++){
            CellGroup g=egg.cellgroups[k];
            for(int i=0;i<g.cellQty;i++){
                Cell c=new Cell();
                c.inputs=new Input[g.inputQtyPerCell];
                for(int j=0;j<g.inputQtyPerCell;j++){
                    c.inputs[j]=new Input();
                    c.inputs[j].cell=c;
                    Zone.copyXY(randomPosInZone(g.groupInputZone),c.inputs[j]);
                    c.inputs[j].radius=g.cellInputRadius;
                }
                c.outputs=new Output[g.outputQtyPerCell];
                for(int j=0;j<g.outputQtyPerCell;j++){
                    c.outputs[j]=new Output();
                    c.outputs[j].cell=c;
                    Zone.copyXY(randomPosInZone(g.groupOutputZone),c.outputs[j]);
                    c.outputs[j].radius=g.cellOutputRadius;
                }

                //将从egg里复制或者生成的cell添加到forg里的cells容器里
                cells.add(c);

            }
        }
    }

    public boolean active(Env env){
        if (!alive)
            return false;
        else if (x < 0 || x >= env.ENV_XSIZE || y < 0 || y >= env.ENV_YSIZE) {// 越界者死！
            alive = false;
            return false;
        }

        for (Cell cell : cells) {
            for (Output output : cell.outputs) {
                if (moveUp.nearby(output))
                    moveUp(env);
                if (moveDown.nearby(output))
                    moveDown(env);
                if (moveLeft.nearby(output))
                    moveLeft(env);
                if (moveRight.nearby(output))
                    moveRight(env);
                if (moveRandom.nearby(output))
                    moveRandom(env);
            }
        }

        return true;
    }

    private void checkFoodAndEat(Env env){
        if(x>=0 && x<env.ENV_XSIZE&&y>=0&&y<env.ENV_YSIZE){
            if(env.foods[x][y]>0){         //判断当前坐标是否有食物
                env.foods[x][y]=0;         //吃掉食物
                energy+=1000;             //能量值增加1000

            }
        }
    }

    private void moveRandom(Env env) {
        int ran = r.nextInt(4);
        if (ran == 0)
            moveUp(env);
        if (ran == 1)
            moveDown(env);
        if (ran == 2)
            moveLeft(env);
        if (ran == 3)
            moveRight(env);
    }

    private void moveUp(Env env) {
        y += 1;
        if (y < 0 || y >= env.ENV_YSIZE) {
            alive = false;
            return;
        }
        checkFoodAndEat(env);
    }

    private void moveDown(Env env) {
        y -= 1;
        if (y < 0 || y >= env.ENV_YSIZE) {
            alive = false;
            return;
        }
        checkFoodAndEat(env);
    }

    private void moveLeft(Env env) {
        x -= 1;
        if (x < 0 || x >= env.ENV_XSIZE
        ) {
            alive = false;
            return;
        }
        checkFoodAndEat(env);
    }

    private void moveRight(Env env) {
        x += 1;
        if (x < 0 || x >= env.ENV_XSIZE) {
            alive = false;
            return;
        }
        checkFoodAndEat(env);
    }

    private float percet1(float f) {
        if (!allowVariation)
            return f;
        return (float) (f * (0.99f + r.nextFloat() * 0.02));
    }

    private float percet5(float f) {
        if (!allowVariation)
            return f;
        return (float) (f * (0.95f + r.nextFloat() * 0.10));
    }

    public static Zone randomPosInZone(Zone z){

        return new Zone(z.x-z.radius+2*z.radius*r.nextFloat(),z.y-z.radius+2*z.radius*r.nextFloat(),
                0);
    }

    public Egg layEgg(){
        if (r.nextInt(100) > 25) // 变异率先固定在25%
            allowVariation = false;// 如果不允许变异，下的蛋就相当于克隆原来的蛋
        else
            allowVariation = true;
        Egg newEgg = new Egg();
        newEgg.brainRadius = percet5(egg.brainRadius);
        CellGroup[] cellgroups = new CellGroup[egg.cellgroups.length];
        newEgg.cellgroups = cellgroups;
        for (int i = 0; i < cellgroups.length; i++) {
            CellGroup cellGroup = new CellGroup();
            cellgroups[i] = cellGroup;
            CellGroup oldGp = egg.cellgroups[i];
            cellGroup.groupInputZone = new Zone(percet5(oldGp.groupInputZone.x), percet5(oldGp.groupInputZone.y),
                    percet5(oldGp.groupInputZone.radius));
            cellGroup.groupOutputZone = new Zone(percet5(oldGp.groupOutputZone.x), percet5(oldGp.groupOutputZone.y),
                    percet5(oldGp.groupOutputZone.radius));
            cellGroup.cellQty = Math.round(percet5(oldGp.cellQty));
            cellGroup.cellInputRadius = percet1(oldGp.cellInputRadius);
            cellGroup.cellOutputRadius = percet1(oldGp.cellOutputRadius);
            cellGroup.inputQtyPerCell = Math.round(percet5(oldGp.inputQtyPerCell));
            cellGroup.outputQtyPerCell = Math.round(percet5(oldGp.outputQtyPerCell));
        }
        return newEgg;
    }


    public void show(Graphics g){
        if(!alive)
            return;
        g.drawImage(frogImg,x-8,y-8,16,16,null);
    }
}
